/**
 * Copyright(c) 2014 Xunton Solutions
 *
 * History:
 *   15-1-17 下午5:02 Created by dwzhang
 */
package com.jade.modules.cms.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.TransactionAttribute;
import javax.inject.Inject;
import javax.inject.Named;

import com.jade.framework.base.criterion.Criteria;
import com.jade.framework.base.criterion.Order;
import com.jade.framework.base.criterion.Restrictions;
import com.jade.framework.base.util.PagingList;
import com.jade.modules.cms.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;

/**
 * 分类管理器实现。
 *
 * @author <a href="mailto:dwzhang@xunton.com">dwzhang</a>
 * @version 1.0 15-1-17 下午5:02
 */
//@Named ("module_cmsCategoryManager")
public class CategoryManagerImpl implements CategoryManager
{
    private CategoryDao dao;

//    @Inject
    public void setDao(@Named ("module_cmsCategoryDao") CategoryDao dao)
    {
        this.dao = dao;
    }

    protected CmsCategory getCategoryByName(String ownerType, String ownerId, long parentId, String name)
    {
        Criteria criteria = new Criteria(0, 1);
        criteria.add(Restrictions.eq("ownerType", ownerType));
        criteria.add(Restrictions.eq("ownerId", ownerId));
        criteria.add(Restrictions.eq("parentId", parentId));
        criteria.add(Restrictions.eq("name", name));
        List<CmsCategory> categories = list(ownerType, ownerId, criteria, false);
        return categories.isEmpty() ? null : categories.get(0);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void add(CmsCategory cmsCategory)
            throws CmsException
    {
        if (getCategoryByName(cmsCategory.getOwnerType(), cmsCategory.getOwnerId(), cmsCategory.getParentId(),
                cmsCategory.getName()) != null) {
            throw new CmsException(CmsConstants.ERR_CATEGORY_NAME_CONFLICT, "name conflict", null,
                    cmsCategory.getName());
        }
        cmsCategory.setCreationDate(new Date());
        cmsCategory.setUpdateDate(cmsCategory.getCreationDate());
        dao.add(cmsCategory);
        List<CmsCategory> children = cmsCategory.getChildren();
        if (children != null) {
            for (CmsCategory child : children) {
                child.setParentId(cmsCategory.getId());
                dao.add(child);
            }
        }
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void update(CmsCategory cmsCategory)
            throws CmsException
    {
        CmsCategory old = getCategoryByName(cmsCategory.getOwnerType(), cmsCategory.getOwnerId(),
                cmsCategory.getParentId(), cmsCategory.getName());
        if (old != null && old.getId() != cmsCategory.getId()) {
            throw new CmsException(CmsConstants.ERR_CATEGORY_NAME_CONFLICT, "name conflict", null,
                    cmsCategory.getName());
        }
        Date now = new Date();
        cmsCategory.setUpdateDate(now);
        dao.update(cmsCategory);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void updateStatus(int status, long... ids)
            throws CmsException
    {
        for (long id : ids) {
            CmsCategory cmsCategory = get(id, false);
            if (cmsCategory != null) {
                cmsCategory.setStatus(status);
                cmsCategory.setUpdateDate(new Date());
                dao.update(cmsCategory);
            }
        }
    }

    public CmsCategory get(long id, boolean children)
    {
        CmsCategory cmsCategory = dao.get(id);
        if (!children) {
            return cmsCategory;
        }
        if (cmsCategory == null) {
            return null;
        }
        //这里存在一个问题，当一个分类的所有者为系统时，其子分类可能是很多其他的所有者。这种情况下列出其所有子分类没有
        //意义，因此这里只考虑其下通用属于系统的子分类。
        cmsCategory.setChildren(
                listChildren(cmsCategory.getOwnerType(), cmsCategory.getOwnerId(), cmsCategory.getId(), children));
        return cmsCategory;
    }

    public CmsCategory getWithFlag(long id)
    {
        CmsCategory category = get(id, false);
        if (category != null) {
            setCategoryFlag(category);
        }
        return category;
    }

    protected void setCategoryFlag(CmsCategory category)
    {
        CmsCategory parent = null;
        if (category.getParentId() != 0) {
            parent = get(category.getParentId(), false);
            setCategoryFlag(parent);
        }
        if (parent != null) {
            if (category.getTitleImageFlag() == CmsConstants.FLAG_INHERIT) {
                category.setTitleImageFlag(parent.getTitleImageFlag());
            }
            if (category.getShareFlag() == CmsConstants.FLAG_INHERIT) {
                category.setShareFlag(parent.getShareFlag());
            }
            if (category.getCommentFlag() == CmsConstants.FLAG_INHERIT) {
                category.setCommentFlag(parent.getCommentFlag());
            }
            if (category.getLikeFlag() == CmsConstants.FLAG_INHERIT) {
                category.setLikeFlag(parent.getLikeFlag());
            }
            if (StringUtils.isBlank(category.getDefaultTitleImage())) {
                category.setDefaultTitleImage(parent.getDefaultTitleImage());
            }
        }
    }


    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void remove(long... ids)
            throws CmsException
    {
        for (long id : ids) {
            CmsCategory cmsCategory = get(id, false);
            if (cmsCategory != null) {
                dao.remove(cmsCategory);
            }
        }
    }

    public PagingList<CmsCategory> query(String ownerType, String ownerId, Criteria criteria, boolean children)
    {
        PagingList<CmsCategory> list = dao.query(ownerType, ownerId, criteria);
        if (!children) {
            return list;
        }
        for (CmsCategory cmsCategory : list) {
            cmsCategory.setChildren(listChildren(ownerType, ownerId, cmsCategory.getId(), true));
        }
        return list;
    }

    public PagingList<CmsCategory> query(Criteria criteria, boolean children)
    {
        PagingList<CmsCategory> list = dao.query(criteria);
        if (!children) {
            return list;
        }
        for (CmsCategory cmsCategory : list) {
            cmsCategory.setChildren(
                    listChildren(cmsCategory.getOwnerType(), cmsCategory.getOwnerId(), cmsCategory.getId(), true));
        }
        return list;
    }

    public List<CmsCategory> list(String ownerType, String ownerId, Criteria criteria, boolean children)
    {
        List<CmsCategory> list = dao.list(ownerType, ownerId, criteria);
        if (!children) {
            return list;
        }
        for (CmsCategory cmsCategory : list) {
            cmsCategory.setChildren(listChildren(ownerType, ownerId, cmsCategory.getId(), true));
        }
        return list;
    }

    public List<CmsCategory> listChildren(String ownerType, String ownerId, long parentId, boolean recursion)
    {
        Criteria criteria = new Criteria();
        criteria.add(Restrictions.eq("parentId", parentId));
        criteria.addOrder(Order.desc("sortCode"));
        return list(ownerType, ownerId, criteria, recursion);
    }


    public List<Long> listChildrenIds(String ownerType, String ownerId, long parentId, boolean recursion)
    {
        List<CmsCategory> categories = listChildren(ownerType, ownerId, parentId, recursion);
        List<Long> ids = new ArrayList<Long>();
        addIdToList(ids, categories);
        return ids;
    }

    protected void addIdToList(List<Long> ids, List<CmsCategory> categories)
    {
        for (CmsCategory cmsCategory : categories) {
            ids.add(cmsCategory.getId());
            if (cmsCategory.getChildren() != null) {
                addIdToList(ids, cmsCategory.getChildren());
            }
        }
    }
}
